﻿using System;
using System.Web;
using System.Web.Hosting;
using System.Net.Mime;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Text;

namespace WebServer
{
	/// <summary>
	/// Provides a base for elements that can be attached to a WebObject instance
	/// </summary>
	public class WebObjectElement : IWebObjectElement,IDisposable
	{
		private IWebObject _Parent = null;
		/// <summary>
		/// Gets or Sets the WebObject instance that this Element is attached to
		/// </summary>
		public IWebObject Parent { get { return _Parent; } set { _Parent = value; } }

		private string _OpenTag = String.Empty;
		/// <summary>
		/// Gets or Sets the opening tag used by this Element
		/// </summary>
		public string OpenTag { get { return _OpenTag; } set { _OpenTag = value; } }

		private string _CloseTag = String.Empty;
		/// <summary>
		/// Gets or Sets the closing tag used by this Element
		/// </summary>
		public string CloseTag { get { return _CloseTag; } set { _CloseTag = value; } }

		private string _Name = String.Empty;
		/// <summary>
		/// Gets or Sets the Name of this Element
		/// </summary>
		public string Name { get { return _Name; } set { _Name = value; } }

		private string _ID = String.Empty;
		/// <summary>
		/// Gets or Sets the unique ID of this Element
		/// </summary>
		public string ID { get { return _ID; } set { _ID = value; } }

		private Dictionary<string, bool> _Lines = new Dictionary<string, bool>();
		/// <summary>
		/// Gets a list of strings that form the structure of this Element
		/// </summary>
		public Dictionary<string, bool> Lines { get { return _Lines; } }

		private string _Content = String.Empty;
		/// <summary>
		/// Gets or Sets the compiled Content code for this Element
		/// </summary>
		public string Content { get { return _Content; } set { _Content = value; } }

		/// <summary>
		/// Creates an instance of WebObjectElement
		/// </summary>
		/// <param name="parent">The WebObject instance that this WebObjectElement is attached to</param>
		/// <param name="name">The Name of this WebObjectElement</param>
		/// <param name="id">The Unique ID for this WebObjectElement</param>
		public WebObjectElement(IWebObject parent, string name, string id)
		{
			_Parent = parent;
			_Name = name;
			_ID = id;
		}

		/// <summary>
		/// Adds an 'html' element to this WebObjectElement
		/// </summary>
		/// <param name="html">HTML code</param>
		public virtual void AddHTML(string html)
		{
			_Lines.Add(html, true);
		}

		/// <summary>
		/// Adds an 'html' element to this WebObjectElement with formatted code
		/// </summary>
		/// <param name="format">String format</param>
		/// <param name="args">Format arguments</param>
		public virtual void AddHTML(string format, params object[] args)
		{
			_Lines.Add(String.Format(format, args), true);
		}

		/// <summary>
		/// Adds a 'text' element to this WebObjectElement
		/// </summary>
		/// <param name="text">Plain text</param>
		public virtual void AddText(string text)
		{
			_Lines.Add(text, true);
		}

		/// <summary>
		/// Adds a 'text' element to this WebObjectElement with formatting
		/// </summary>
		/// <param name="format">String format</param>
		/// <param name="args">Format arguments</param>
		public virtual void AddText(string format, params object[] args)
		{
			_Lines.Add(String.Format(format, args), true);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="b"></param>
		public virtual void AddByte(byte b)
		{
			_Lines.Add(Encoding.Default.GetString(new byte[] { b }), false);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="bytes"></param>
		public virtual void AddByte(byte[] bytes)
		{
			_Lines.Add(Encoding.Default.GetString(bytes), false);
		}

		/// <summary>
		/// Compiles all strings (Lines) associated with this WebObjectElement into a single Content string before being compiled into the parent WebObject
		/// </summary>
		/// <returns>Content of this WebObjectElement, compiled into a single string</returns>
		public virtual string Compile()
		{
			if (!String.IsNullOrEmpty(_OpenTag))
				_Content = _OpenTag;
			else
				_Content = String.Empty;

			foreach (KeyValuePair<string, bool> kvp in _Lines)
			{
				_Content += kvp.Key + (kvp.Value ? "\n" : String.Empty);
			}

			if (!String.IsNullOrEmpty(_CloseTag))
				_Content += _CloseTag;

			OnCompile();

			return _Content;
		}

		/// <summary>
		/// Effectively nulliefies all variables, and clears all arrays associated with this WebObjectElement.
		/// </summary>
		public void Dispose()
		{
			_ID = null;
			_Name = null;
			_OpenTag = null;
			_CloseTag = null;
			_Parent = null;
			_Content = null;
			_Lines.Clear();
		}

		/// <summary>
		/// Fired when this Element is compiled
		/// </summary>
		public virtual void OnCompile() { }

		/// <summary>
		/// Fired just before this Element is compiled and determines whether this Element should be Compiled
		/// </summary>
		/// <returns>Returns 'true' by default, can be overridden in a derived class to determine whether this Element should be compiled or not</returns>
		public virtual bool OnBeforeCompile() { return true; }

		/// <summary>
		/// Fired just after this Element is successfully compiled
		/// </summary>
		public virtual void OnAfterCompile() { }
	}
}
